package main

import (
	"context"
	"fmt"
	"time"
)

/*
简化在多个go routine传递上下文数据，并将多个groutine之间关联起来。控制goroutine的生命周期。
*/

func main() {

	// ContextWithCancel()     // 手动结束
	// TestWithValue()
	// ContextWithTimeout()    // 函数可以设置多长时间结束
	ContextWithDeadLine() // 设置一个时间点结束

}

// 延时结束
func ContextWithDeadLine() {
	d := time.Now().Add(5 * time.Second)
	ctx111, cancel := context.WithDeadline(context.Background(), d)
	defer cancel()
	ctx222 := context.WithValue(ctx111, "key2", "value2")
	go watch(ctx222)
	time.Sleep(8 * time.Second)
	fmt.Println("通知监控停止")

}

// 多少秒后结束
func ContextWithTimeout() {
	ctx11, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	ctx22 := context.WithValue(ctx11, "key2", "value2")
	go watch(ctx22)
	time.Sleep(8 * time.Second)
	fmt.Println("通知监控停止")

}

// withValue可以设置一个key/value的键值对，可以在下游任何一个嵌套的context中通过key获取value。
func TestWithValue() {
	root := context.Background()
	ctx1 := context.WithValue(root, "key1", "value1")
	ctx2 := context.WithValue(ctx1, "key2", "value2")
	fmt.Println(ctx1.Value("key1"))
	fmt.Println(ctx1.Value("key11"))
	fmt.Println(ctx2.Value("key2"))
}

// 手动结束
func ContextWithCancel() {
	root := context.Background()
	//ctx1, cancel := context.WithDeadline(root, time.Now().Add(6 * time.Second))
	ctx1, cancel := context.WithCancel(root)
	// WithValue可以设置一个key/value的键值对，可以在下游任何一个嵌套的context中通过key获取value。
	ctx2 := context.WithValue(ctx1, "key2", "value2")
	go watch(ctx2)
	time.Sleep(8 * time.Second)
	fmt.Println("通知监控停止")
	cancel()
	time.Sleep(5 * time.Second)
}

func watch(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println(ctx.Value("key2"), "监控退出了。")
			return
		default:
			fmt.Println(ctx.Value("key2"), "go rountine 监控中。。。")
			time.Sleep(2 * time.Second)
		}
	}
}
